﻿using System;
using System.IO;
using System.Collections.Generic;
using SynergyCounts.DataContext;
using System.Linq;
using System.Xml;

namespace SynergyCounts
{
    sealed class Presenter
    {
        private readonly ISynergyDFCView synergyDFCView;
        private readonly IModel model;

        public Presenter(ISynergyDFCView synergyDFCView, IModel model)
        {
            this.synergyDFCView = synergyDFCView;
            this.model = model;

            synergyDFCView.LinksSelected += OnLinksRequested;
            synergyDFCView.MCVFileSelected += OnMCVFileSelected;
            synergyDFCView.ConditionsSelected += OnConditionsSelected;
            synergyDFCView.ExportXMLRequested += OnExportXMLRequested;
        }

        private void OnLinksRequested()
        {
            try
            {
                IReadOnlyList<NavLink> list = model.GetSelectedNavLinks();
                SetTotalLinksCount(list);
                SetNoTrucksLinkCount(list);
                SetDividerLinkCount(list);
            }
            catch
            {
                synergyDFCView.ExceptionMessage = "Turn on AtlasWebService plugin";
            }
        }

        private void OnMCVFileSelected()
        {
            // added ToLower() and all midcover names changed to text with lower registr.
            String filesData = ReadFilesDataToString(synergyDFCView.SelectedMCVFilePath).ToLower();

            synergyDFCView.AccessMCVCount = CountParticularMCVType(new[] { "|access" }, filesData);
            synergyDFCView.BridgeTunnelMCVCount = CountParticularMCVType(new[] { "|bridge/bunnel" }, filesData);
            synergyDFCView.TollBoothMCVCount = CountParticularMCVType(new[] { "|toll booth" }, filesData);
            synergyDFCView.UnpavedMCVCount = CountParticularMCVType(new[] { "|unpaved", "|paved" }, filesData);
            synergyDFCView.DOTMCVCount = CountParticularMCVType(new[] { "|dot", "|oneway" }, filesData);
            synergyDFCView.RDMMCVCount = CountParticularMCVType(new[] { "|rdm", "|no u-turn", "|no left turn", "|no right turn" }, filesData);
            synergyDFCView.DividerMCVCount = CountParticularMCVType(new[] { "|divider", "|open div", "|closed div", "|legal" }, filesData);
            synergyDFCView.DistanceMarkerMCVCount = CountParticularMCVType(new[] { "|distance marker", "dm" }, filesData);
            synergyDFCView.GateMCVCount = CountParticularMCVType(new[] { "|gate", "|key gate", "|permission gate", "|emergency gate" }, filesData);
            synergyDFCView.ZLevelMCVCount = CountParticularMCVType(new[] { "|z-level", "|over pass", "|under pass" }, filesData);
            synergyDFCView.TransportMCVCount = CountParticularMCVType(new[] { "|transport" }, filesData);
            synergyDFCView.POIMCVCount = CountParticularMCVType(new[] { "|poi" }, filesData);
            synergyDFCView.DACOMRSEStopMCVCount = CountParticularMCVType(new[] { "|da", "|cont of main road", "|comr", "|se", "|special explication", "|stop" }, filesData);
            synergyDFCView.ADASMCVCount = CountParticularMCVType(new[] { "|adas" }, filesData);
            synergyDFCView.TrafficSignalPedTrafficLightMCVCount = CountParticularMCVType(new[] { "|traffic signal", "|ped traffic light" }, filesData);
            synergyDFCView.PedCrossingMCVCount = CountParticularMCVType(new[] { "|ped crossing" }, filesData);
            synergyDFCView.PriorityMCVCount = CountParticularMCVType(new[] { "|priority", "|yield", "|prio frm right" }, filesData);
            synergyDFCView.TotalMCVCount = GetTotalMCVCount(filesData);
        }

        private void OnConditionsSelected()
        {
            CountLinksWithConditions();
        }

        private void OnExportXMLRequested()
        {
            ConvertMidcoversToXML(synergyDFCView.SaveXMLFilePath);
        }

        private void SetTotalLinksCount(IReadOnlyList<NavLink> list)
        {
            synergyDFCView.TotalLinkCount = list.Count;
        }

        private void SetNoTrucksLinkCount(IReadOnlyList<NavLink> list)
        {
            Int32 count = 0;
            foreach (var item in list)
            {
                if (item.accessTrucks == false)
                {
                    count += 1;
                }
            }
            synergyDFCView.NoTrucksLinkCount = count;
        }
         // new method ---------------
        private void SetDividerLinkCount(IReadOnlyList<NavLink> list)
        {
            Int32 count = 0;
            foreach (var item in list)
            {
                if (item.divider != "N")
                {
                    count += 1;
                }
            }
            synergyDFCView.DividerLinkCount = count;
        }

        private Int32 CountParticularMCVType(String[] MCVname, String fileData)
        {
            String[] temp = fileData.Split(MCVname, StringSplitOptions.None);
            return temp.Length - 1;
        }

        private Int32 GetTotalMCVCount(String fileData)
        {
            String[] temp = fileData.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            return temp.Length;
        }

        private void CountLinksWithConditions()
        {
            IReadOnlyList<Condition> conditions = Condition.ConditionParser(synergyDFCView.Conditions);

            synergyDFCView.TARLinkCount = conditions
                .Where(condition => condition.conditionType
                    .Contains("TRANSPORT ACCESS RESTRICTION"))
                    .GroupBy(condition => condition.sourceLinkID)
                    .Select(condition => condition.First())
                    .Count();

            synergyDFCView.TRDMConditionCount = conditions
                .Where(condition => condition.conditionType
                    .Contains("TRANSPORT RDM"))
                    .Count();

            synergyDFCView.TSSSLinkCount = conditions
                .Where(condition => condition.conditionType
                    .Contains("TRANSPORT SPCL SPD SITUATION"))
                    .GroupBy(condition => condition.sourceLinkID)
                    .Select(condition => condition.First())
                    .Count();

            synergyDFCView.SpecialVariableSpeedLinkCount = conditions
                .Where(condition => condition.conditionType.Contains("SPECIAL SPEED SITUATION") || condition.conditionType.Contains("VARIABLE SPEED LIMIT"))
                    .GroupBy(condition => condition.sourceLinkID)
                    .Select(condition => condition.First())
                    .Count();
            // ------------ remaked block ---------------------
            synergyDFCView.TransportTrafficSignLinkCount = conditions
                .Where(condition => condition.conditionType.Contains("TRAFFIC SIGN-END OF LOW GEAR") || 
                    condition.conditionType.Contains("TRAFFIC SIGN-END OF NO ENGINE BRAKE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-END OF NO OVERTAKING TRUCKS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-LOW GEAR") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-NO ENGINE BRAKE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-NO IDLING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-RISK OF GROUNDING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-START OF NO OVERTAKING TRUCKS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-TRUCK ROLLOVER"))
                    .GroupBy(condition => condition.sourceLinkID)
                    .Select(condition => condition.First())
                    .Count();

            synergyDFCView.DACOMRSELinkCount = conditions
                .Where(condition => condition.conditionType.Contains("TRAFFIC SIGN-ACCIDENT HAZARD") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-ANIMAL CROSSING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-BICYCLE CROSSING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-CONGESTION HAZARD") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-CROSSING WITH PRIORITY FROM THE RIGHT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-DOUBLE HAIRPIN") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-EMBANKMENT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-END OF ALL RESTRICTIONS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-END OF NO OVERTAKING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-FALLING ROCKS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-FLOOD AREA") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-GENERAL CURVE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-GENERAL HILL") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-GENERAL WARNING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-HORN SIGN") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-HUMP BRIDGE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-ICY CONDITIONS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-LANE MERGE CENTRE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-LANE MERGING FROM THE LEFT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-LANE MERGING FROM THE RIGHT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-LATERAL WIND") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-OBSTACLE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-PEDESTRIAN CROSSING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-PRIORITY OVER ONCOMING TRAFFIC") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-PROTECTED OVERTAKING - EXTRA LANE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-PROTECTED OVERTAKING - EXTRA LANE LEFT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-PROTECTED OVERTAKING - EXTRA LANE RIGHT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-RAILWAY CROSSING PROTECTED") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-RAILWAY CROSSING UNPROTECTED") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-ROAD NARROWS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-SCHOOL ZONE") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-SHARP CURVE LEFT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-SHARP CURVE RIGHT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-SLIPPERY ROAD") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-START OF NO OVERTAKING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-STEEP HILL DOWNWARDS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-STEEP HILL UPWARDS") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-STOP SIGN") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-TRAMWAY CROSSING") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-TRIPLE HAIRPIN") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-TWO-WAY TRAFFIC") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-UNEVEN ROAD") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-URBAN AREA") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-WINDING ROAD STARTING LEFT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-WINDING ROAD STARTING RIGHT") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-YIELD") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-YIELD TO BICYCLES") ||
                    condition.conditionType.Contains("TRAFFIC SIGN-YIELD TO ONCOMING TRAFFIC") ||
                    condition.conditionType.Contains("THROUGH ROUTE") ||
                    condition.conditionType.Contains("SPECIAL EXPLICATION"))
                    .GroupBy(condition => condition.sourceLinkID)
                    .Select(condition => condition.First())
                    .Count();
        }
        //Strange descision. Review later.
        private void ConvertMidcoversToXML(String outputFilePath)
        {
            if (synergyDFCView.SelectedMCVFilePath == null)
                return;
            String filesData = ReadFilesDataToString(synergyDFCView.SelectedMCVFilePath);
            IReadOnlyList<Midcover> midcovers = new Midcover().MidcoverParser(filesData).ToArray();

            XmlDocument xml = new XmlDocument();
            xml.PreserveWhitespace = true;

            XmlNode dataSet = xml.CreateNode(XmlNodeType.Element, "DataSet", String.Empty);
            xml.AppendChild(dataSet);

            XmlNode inputDef = xml.CreateNode(XmlNodeType.Element, "InputDef", String.Empty);
            XmlNode headerRow = xml.CreateNode(XmlNodeType.Element, "HeaderRow", String.Empty);
            XmlNode dataRows = xml.CreateNode(XmlNodeType.Element, "DataRows", String.Empty);
            XmlNode invalidRows = xml.CreateNode(XmlNodeType.Element, "InvalidRows", String.Empty);
            dataSet.AppendChild(inputDef);
            dataSet.AppendChild(headerRow);
            dataSet.AppendChild(dataRows);
            dataSet.AppendChild(invalidRows);

            XmlNode originalFileName = xml.CreateNode(XmlNodeType.Element, "OriginalFileName", String.Empty);
            originalFileName.InnerText = outputFilePath;
            XmlNode delimitedFormat = xml.CreateNode(XmlNodeType.Element, "DelimitedFormat", String.Empty);
            inputDef.AppendChild(originalFileName);
            inputDef.AppendChild(delimitedFormat);

            XmlNode headerLabel1 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            XmlNode headerLabel2 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            XmlNode headerLabel3 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            headerLabel3.InnerText = "LATITUDE";
            XmlNode headerLabel4 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            headerLabel4.InnerText = "LONGITUDE";
            XmlNode headerLabel5 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            XmlNode headerLabel6 = xml.CreateNode(XmlNodeType.Element, "HeaderLabel", String.Empty);
            headerLabel6.InnerText = "DESCRIPTION";

            headerRow.AppendChild(headerLabel1);
            headerRow.AppendChild(headerLabel2);
            headerRow.AppendChild(headerLabel3);
            headerRow.AppendChild(headerLabel4);
            headerRow.AppendChild(headerLabel5);
            headerRow.AppendChild(headerLabel6);

            for (int i = 0; i < midcovers.Count; i++)
            {
                XmlNode dataRow = xml.CreateNode(XmlNodeType.Element, "DataRow", String.Empty);
                XmlAttribute status = xml.CreateAttribute("status");
                status.InnerText = "New";
                XmlAttribute rowNum = xml.CreateAttribute("rowNum");
                rowNum.InnerText = (i).ToString();
                XmlAttribute requested = xml.CreateAttribute("requested");
                requested.InnerText = "No";
                dataRow.Attributes.Append(status);
                dataRow.Attributes.Append(rowNum);
                dataRow.Attributes.Append(requested);
                dataRows.AppendChild(dataRow);

                XmlNode remarks = xml.CreateNode(XmlNodeType.Element, "Remarks", String.Empty);
                XmlNode errorMessage = xml.CreateNode(XmlNodeType.Element, "ErrorMessage", String.Empty);
                XmlNode latitude = xml.CreateNode(XmlNodeType.Element, "Latitude", String.Empty);
                latitude.InnerText = midcovers[i].xCoordinate.ToString();
                XmlNode longitude = xml.CreateNode(XmlNodeType.Element, "Longitude", String.Empty);
                longitude.InnerText = midcovers[i].yCoordinate.ToString();
                XmlNode description = xml.CreateNode(XmlNodeType.Element, "Description", String.Empty);
                description.InnerText = midcovers[i].information;
                XmlNode linkID = xml.CreateNode(XmlNodeType.Element, "LinkID", String.Empty);
                linkID.InnerText = "0";
                XmlNode linkPVID = xml.CreateNode(XmlNodeType.Element, "LinkPVID", String.Empty);
                linkPVID.InnerText = "0";
                XmlNode nodeID = xml.CreateNode(XmlNodeType.Element, "NodeID", String.Empty);
                nodeID.InnerText = "0";
                XmlNode nodePVID = xml.CreateNode(XmlNodeType.Element, "NodePVID", String.Empty);
                nodePVID.InnerText = "0";
                XmlNode postalCode = xml.CreateNode(XmlNodeType.Element, "PostalCode", String.Empty);
                XmlNode city = xml.CreateNode(XmlNodeType.Element, "City", String.Empty);
                XmlNode address = xml.CreateNode(XmlNodeType.Element, "Address", String.Empty);

                dataRow.AppendChild(remarks);
                dataRow.AppendChild(errorMessage);
                dataRow.AppendChild(latitude);
                dataRow.AppendChild(longitude);
                dataRow.AppendChild(description);
                dataRow.AppendChild(linkID);
                dataRow.AppendChild(linkPVID);
                dataRow.AppendChild(nodeID);
                dataRow.AppendChild(nodePVID);
                dataRow.AppendChild(postalCode);
                dataRow.AppendChild(city);
                dataRow.AppendChild(address);
            }

            {
                XmlNode invalidRow = xml.CreateNode(XmlNodeType.Element, "InvalidRow", String.Empty);
                XmlNode errorMessage = xml.CreateNode(XmlNodeType.Element, "ErrorMessage", String.Empty);
                invalidRows.AppendChild(invalidRow);
                invalidRows.AppendChild(errorMessage);
            }

            String temp = xml.InnerXml;
            xml.Save(outputFilePath);
        }

        private String ReadFilesDataToString(String[] filesPath)
        {
            String filesData = null;
            for (Int32 i = 0; i < synergyDFCView.SelectedMCVFilePath.Length; i++)
            {
                using (StreamReader stream = new StreamReader(synergyDFCView.SelectedMCVFilePath[i]))
                {
                    filesData += stream.ReadToEnd() + "\n";
                }
            }
            return filesData;
        }

        public void Start()
        {
            synergyDFCView.ShowView();
        }
    }
}